﻿/**
 * ...
 * @author Krzysztof Rozalski
 */

package hapi.util.profiler.flash;

import haxe.Timer;

import hapi.event.HapiDispatcher;
import hapi.event.Notifier;

#if flash9
typedef FPSTarget = flash.display.Stage;
import flash.events.Event;
#elseif flash
typedef FPSTarget = flash.MovieClip;
#else
typedef FPSTarget = nme.display.Stage;
import nme.events.Event;
#end

typedef FrameRateEvent = {
	var currentRate:Int;
	var averageRate:Float;
}

class FrameRateMeter {

	static var inst:FrameRateMeter;
	
	var timer:Timer;
	var overallDuration:Float;
	var target:FPSTarget;
	public var currentRate(default,null):Int;
	public var averageRate(default,null):Float;
	
	var stampSinceLastRefresh:Float;
	var framesPassedSinceLastRefresh:Int;
	
	var frameRatesSumSinceStart:Int;
	var secondsPassedSinceStart:Int;
	
	var frameRateUpdateDispatcher:HapiDispatcher<FrameRateEvent>;
	public var onFrameRateUpdate(getFrameRateNotifier,null):Notifier<FrameRateEvent>;
	
	public function new(?target=null) {
		frameRateUpdateDispatcher = new hapi.event.HapiDispatcher();
		#if (flash9 || cpp || neko)
		this.target = target == null ? flash.Lib.current.stage : target;
		#elseif flash
		this.target = target == null ? flash.Lib.current.createEmptyMovieClip("__hapi_fps_meter__", -9999128) : target;
		this.target._x = this.target._y = -2000;
		#end
		start();
	}
	
	public static function getStageMeter(){
		if(inst == null){
			inst = new FrameRateMeter();
		}
		return inst;
	}
	
	public function start(){
		resetParameters();
		timer = new Timer(10);
		timer.run = refreshFrameRate;
		#if (flash9 || cpp || neko)
		target.addEventListener(Event.ENTER_FRAME, onEnterFrame);
		#elseif flash
		target.onEnterFrame = onEnterFrame;
		#end
	}
	
	public function stop() {
		timer.stop();
		#if (flash9 || cpp || neko)
		target.removeEventListener(flash.events.Event.ENTER_FRAME, onEnterFrame);
		#elseif flash
		Reflect.deleteField(target, "onEnterFrame");
		#end
		currentRate = 0;
	}
	
	function refreshFrameRate() {
		if( secondPassedSinceLastRefresh()  ){
			updateFrameRate(framesPassedSinceLastRefresh);
			framesPassedSinceLastRefresh = 0;
			stampSinceLastRefresh = Timer.stamp();
		}
	}
	
	function onEnterFrame(#if (flash9 || cpp || neko) e #end ){
		++framesPassedSinceLastRefresh;
	}
	
	function resetParameters() {
		framesPassedSinceLastRefresh = 0;
		frameRatesSumSinceStart = 0;
		secondsPassedSinceStart = 0;
		stampSinceLastRefresh = Timer.stamp();
	}
	
	inline function secondPassedSinceLastRefresh() {
		return (Timer.stamp() - stampSinceLastRefresh > 1);
	}
	
	function updateFrameRate(newFrameRate:Int) {
		secondsPassedSinceStart++;
		frameRatesSumSinceStart += newFrameRate;
		averageRate = Math.round((frameRatesSumSinceStart / secondsPassedSinceStart) * 100) / 100;
		if ( currentRate != newFrameRate ) {
			currentRate = newFrameRate;
			frameRateUpdateDispatcher.dispatchEvent({currentRate:currentRate, averageRate:averageRate});
		}
	}
	
	function getFrameRateNotifier():hapi.event.Notifier<FrameRateEvent> {
		return frameRateUpdateDispatcher;
	}
}